package com.spica.platform.user.controller;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spica.platform.base.feign.UserFeignClient;
import com.spica.platform.base.model.LoginAppUser;
import com.spica.platform.base.model.PageResult;
import com.spica.platform.base.model.ResponseEntity;
import com.spica.platform.base.model.SysUser;
import com.spica.platform.common.constant.CommonConstant;
import com.spica.platform.common.constant.UserType;
import com.spica.platform.log.annotation.AuditLog;
import com.spica.platform.user.constants.SysUserConstant;
import com.spica.platform.user.exception.SysUserException;
import com.spica.platform.user.exception.SysUserRtnCodEnum;
import com.spica.platform.user.model.SysUserExcel;
import com.spica.platform.user.model.request.SysUserQueryParam;
import com.spica.platform.user.service.ISysUserService;
import com.spica.platform.watermark.ExcelUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.vavr.control.Try;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 用户
 * 接口返回规范:
 * 需要使用ResponseEntity包装
 * 接口命名规范:
 * findXXX, removeXXX, updateXXX, saveXXX
 */
@Slf4j
@RestController
@Api(tags = SysUserConstant.SYS_USER_API)
public class SysUserController implements UserFeignClient {

	@Autowired
	private ISysUserService sysUserService;

	/**
	 * 查询用户实体对象SysUser,返回不带角色和权限的sysUser对象
	 */
	@GetMapping(value = "/users/username", params = "username")
	@ApiOperation(value = SysUserConstant.FIND_SYS_USER_BY_USER_NAME)
	@Cacheable(value = "user", key = "#username", unless = "#result == null")
	public ResponseEntity<SysUser> findSysUserByUsername(@RequestParam("username") String username) {
		return ResponseEntity.of(SysUserRtnCodEnum.SYS_USER_0000C.getRtnCode(), SysUserRtnCodEnum.SYS_USER_0000C.getRtnMessage(), sysUserService.findSysUserByUsername(username));
	}

	/**
	 * 根据userId查询用户信息
	 */
	@GetMapping(value = "/users-anon/userId", params = "userId")
	@ApiOperation(value = "根据UserId查询用户")
	public ResponseEntity<LoginAppUser> findLoginAppUserByUserId(@RequestParam("userId")  String userId) {
		return ResponseEntity.of(SysUserRtnCodEnum.SYS_USER_0000C.getRtnCode(), SysUserRtnCodEnum.SYS_USER_0000C.getRtnMessage(), sysUserService.findLoginAppUserBySysUser(sysUserService.getById(userId)));
	}

	/**
	 * 查询用户登录对象LoginAppUser
	 */
	@GetMapping(value = "/users-anon/username", params = "username")
	@ApiOperation(value = SysUserConstant.FIND_LOGIN_APP_USER_BY_USER_NAME)
	public ResponseEntity<LoginAppUser> findLoginAppUserByUsername(@RequestParam("username") String username) {
		return ResponseEntity.of(SysUserRtnCodEnum.SYS_USER_0000C.getRtnCode(), SysUserRtnCodEnum.SYS_USER_0000C.getRtnMessage(), sysUserService.findLoginAppUserBySysUser(sysUserService.findSysUserByUsername(username)));
	}

	/**
	 * 通过手机号查询用户、角色信息
	 */
	@GetMapping(value = "/users-anon/mobile", params = "mobile")
	@ApiOperation(value = SysUserConstant.FIND_LOGIN_APP_USER_BY_MOBILE)
	public ResponseEntity<LoginAppUser> findLoginAppUserByMobile(@RequestParam("mobile") String mobile) {
		return ResponseEntity.of(SysUserRtnCodEnum.SYS_USER_0000C.getRtnCode(), SysUserRtnCodEnum.SYS_USER_0000C.getRtnMessage(), sysUserService.findLoginAppUserBySysUser(sysUserService.findSysUserByMobile(mobile)));
	}

	/**
	 * 根据OpenId查询用户信息
	 */
	@GetMapping(value = "/users-anon/openId", params = "openId")
	@ApiOperation(value = SysUserConstant.FIND_LOGIN_APP_USER_BY_OPEN_ID)
	public ResponseEntity<LoginAppUser> findLoginAppUserByOpenId(@RequestParam("openId") String openId) {
		return ResponseEntity.of(SysUserRtnCodEnum.SYS_USER_0000C.getRtnCode(), SysUserRtnCodEnum.SYS_USER_0000C.getRtnMessage(), sysUserService.findLoginAppUserBySysUser(sysUserService.findSysUserByOpenId(openId)));
	}

	/**
	 * 用户分页查询信息
	 */
	@GetMapping("/users/list")
	@ApiOperation(value = SysUserConstant.FIND_USERS_BY_PAGE)
	@ApiImplicitParams({ @ApiImplicitParam(name = "page", value = "分页起始位置", required = true, dataType = "Integer"),
			@ApiImplicitParam(name = "limit", value = "分页结束位置", required = true, dataType = "Integer") })
	@AuditLog(operation = " #sysUser.username  + '查看了用户列表'")
	public PageResult<SysUser> findSysUsersByParam(Page<SysUser> page, SysUserQueryParam sysUserQueryParam) {
		return sysUserService.findSysUsersByParam(page, sysUserQueryParam);
	}

	/**
	 * 修改用户状态
	 * 只有超级管理员可以修改
	 */
	@GetMapping("/users/updateAccountStatus")
	@ApiOperation(value = SysUserConstant.UPDATE_USER_ENABLED)
	@ApiImplicitParams({ @ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Integer"),
			@ApiImplicitParam(name = "enabled", value = "是否启用", required = true, dataType = "Boolean") })
	public ResponseEntity updateAccountStatus(SysUserQueryParam sysUserQueryParam) {
		if (checkAdmin(sysUserQueryParam.getId())) {
			return ResponseEntity.failed(SysUserConstant.ADMIN_CHANGE_MSG);
		}

		Try.of(() -> sysUserService.updateAccountStatus(sysUserQueryParam.getId(), sysUserQueryParam.getAccountStatus())).onFailure(ex -> log.error(SysUserRtnCodEnum.SYS_USER_00001.getRtnCode(), ex))
				.getOrElseThrow(item -> new SysUserException(SysUserRtnCodEnum.SYS_USER_00001));

		return ResponseEntity.succeed(SysUserRtnCodEnum.SYS_USER_00002);

	}

	/**
	 * 管理后台，给用户重置密码
	 * 只有超级管理员可以修改
	 */
	@PostMapping(value = "/users/{id}/password")
	@ApiOperation(value = SysUserConstant.UPDATE_RESET_PASSWORD)
	public ResponseEntity resetPassword(@PathVariable Long id) {
		if (checkAdmin(id)) {
			return ResponseEntity.failed(SysUserConstant.ADMIN_CHANGE_MSG);
		}

		Try.of(() -> sysUserService.updatePassword(id, null, null))
				.onFailure(ex -> log.error("user-resetPassword-error", ex))
				.getOrElseThrow(item -> new SysUserException(SysUserRtnCodEnum.SYS_USER_00003));

		return ResponseEntity.succeed(SysUserRtnCodEnum.SYS_USER_00004);
	}

	/**
	 * 用户自己修改密码
	 * 只有超级管理员可以修改
	 */
	@PostMapping(value = "/users/password")
	@ApiOperation(value = SysUserConstant.UPDATE_USER_PASSWORD)
	public ResponseEntity resetPassword(@RequestBody SysUser sysUser) {

		if (checkAdmin(sysUser.getId())) {
			return ResponseEntity.failed(SysUserConstant.ADMIN_CHANGE_MSG);
		}

		Try.of(() -> sysUserService.updatePassword(sysUser.getId(), sysUser.getOldPassword(), sysUser.getNewPassword()))
				.onFailure(ex -> log.error(SysUserRtnCodEnum.SYS_USER_00005.getRtnCode(), ex))
				.getOrElseThrow(item -> new SysUserException(SysUserRtnCodEnum.SYS_USER_00005));

		return ResponseEntity.succeed(SysUserRtnCodEnum.SYS_USER_00006);

	}

	/**
	 * 删除用户和角色信息
	 * 只有超级管理员可以修改
	 */
	@PostMapping(value = "/users/remove/{id}")
	@ApiOperation(value = SysUserConstant.DELETE_USER)
	public ResponseEntity removeUserAndRoleByUserId(@PathVariable Long id) {
		if (checkAdmin(id)) {
			return ResponseEntity.failed(SysUserConstant.ADMIN_CHANGE_MSG);
		}

		Try.of(() -> sysUserService.delUser(id)).onFailure(ex -> log.error(SysUserRtnCodEnum.SYS_USER_00007.getRtnCode(), ex))
				.getOrElseThrow(item -> new SysUserException(SysUserRtnCodEnum.SYS_USER_00007));

		return ResponseEntity.succeed(SysUserRtnCodEnum.SYS_USER_00008);
	}

	/**
	 * 新增or更新
	 *
	 * @param sysUser
	 * @return
	 */
	@SneakyThrows
	@PostMapping("/users/saveOrUpdate")
	//更新用户的信息后,使缓存失效
	@CacheEvict(value = "user", key = "#sysUser.username")
	@AuditLog(operation = "'新增或更新用户:' + #sysUser.username")
	public ResponseEntity saveOrUpdate(@RequestBody SysUser sysUser) {

		Try.of(() -> sysUserService.saveOrUpdateUser(sysUser)).onFailure(ex -> log.error(SysUserRtnCodEnum.SYS_USER_00009.getRtnCode(), ex))
				.getOrElseThrow(item -> new SysUserException(SysUserRtnCodEnum.SYS_USER_00009));

		return ResponseEntity.succeed(SysUserRtnCodEnum.SYS_USER_0000A);

	}

	/**
	 * 导出excel
	 */
	@SneakyThrows
	@GetMapping("/users/export")
	@ApiOperation(value = SysUserConstant.EXPORT_USERS_BY_EXCEL)
	public void exportSysUserExcel(SysUserQueryParam sysUserQueryParam, HttpServletResponse response) {
		List<SysUserExcel> listUsers = sysUserService.findAllUsers(sysUserQueryParam);

		try (Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(null, "用户", ExcelType.XSSF),SysUserExcel.class, listUsers);) {
			Calendar c = Calendar.getInstance();
			Date date = c.getTime();
			String t20 = String.format("%tF", date);
			String file = "users"+t20+".xlsx";
			// 导出excel
			ExcelUtil.exportExcelWithWaterMark(workbook, file, response);
		}

	}

	@SneakyThrows
	@PostMapping(value = "/users/import")
	@ApiOperation(value = SysUserConstant.IMPORT_USERS_BY_EXCEL)
	public ResponseEntity importSysUserExcl(@RequestParam("file") MultipartFile excl) {
		int rowNum = 0;
		if (!excl.isEmpty()) {
			List<SysUserExcel> list = ExcelUtil.importExcel(excl, 0, 1, SysUserExcel.class);
			rowNum = list.size();
			if (rowNum > 0) {
				List<SysUser> users = new ArrayList<>(rowNum);
				list.forEach(u -> {
					SysUser user = new SysUser();
					BeanUtil.copyProperties(u, user);
					user.setPassword(CommonConstant.DEF_USER_PASSWORD);
					user.setType(UserType.BACKEND.getCode());
					users.add(user);
				});
				sysUserService.saveBatch(users);
			}
		}
		return ResponseEntity.succeed("导入数据成功，一共【" + rowNum + "】行");
	}

	/**
	 * 是否超级管理员
	 */
	private boolean checkAdmin(long id) {
		return id == 1L;
	}
}
